package com.hymjweb.demo.hymj.log_manage.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageInfo;
import com.hymjweb.demo.framework.result.MIniUIGridResultMap;
import com.hymjweb.demo.framework.sys.BaseService;
import com.hymjweb.demo.framework.sys.SysConstant;
import com.hymjweb.demo.framework.util.DataTypeUtil;
import com.hymjweb.demo.framework.util.DateUtil;
import com.hymjweb.demo.framework.util.pojoContrast.ContrastUtils;
import com.hymjweb.demo.hymj.log_manage.aop.annotation.OperationLogger;
import com.hymjweb.demo.hymj.log_manage.bean.XtBackupLogMsgPojo;
import com.hymjweb.demo.hymj.log_manage.data_column.service.DataColumnService;
import com.hymjweb.demo.hymj.log_manage.mapper.XtBackupLogMsgMapper;
import org.apache.commons.beanutils.PropertyUtils;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.Table;
import java.beans.PropertyDescriptor;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @author DaTing created on 2020-09-17
 **/
@Service
public class XtBackupLogMsgService extends BaseService {

    @Autowired
    private XtBackupLogMsgMapper xtBackupLogMsgMapper;

    @Autowired
    private DataColumnService dataColumnService;

    @Autowired
    private ContrastUtils contrastUtils;

    /**
     * 添加日志
     * @param originalObject 原来的对象
     * @param operationLogger 这是注解对象
     * @throws Exception
     */
    @Transactional(rollbackFor = {Exception.class})
    public void addLogDirect(Object originalObject, OperationLogger operationLogger) throws Exception {
        // operationLogger.oper(),operationLogger.operTitle(),operationLogger.operMemo(),operationLogger.classType().getName()
        String objId = DataTypeUtil.toNotNullString(DataTypeUtil.getIdValueFromObj(originalObject));
        Table table = (Table) operationLogger.classType().getAnnotation(Table.class);

        // 获取操作之前的对象
        Object newObject = dataColumnService.queryPojoById(table.name(),objId,operationLogger.classType());
        String backupLogMsg = "";
        if(SysConstant.OPER_DELETE.equals(operationLogger.oper())){
            backupLogMsg = JSON.toJSONString(originalObject);
        }
        else if(newObject!=null && SysConstant.OPER_ADD.equals(operationLogger.oper())){
            backupLogMsg = JSON.toJSONString(newObject);
        }
        else{
            backupLogMsg = contrastUtils.compareTwoObj(operationLogger.oper(), originalObject, newObject);
        }

        if(backupLogMsg.trim().length()>0){

            Object tableId = DataTypeUtil.invokeMethod(originalObject,"id");
            XtBackupLogMsgPojo pojo = createLogPojo(newObject.getClass(), DataTypeUtil.toNotNullString(tableId), operationLogger.operTitle(), operationLogger.operMemo(),operationLogger.classType().getName(), backupLogMsg);

            // 改变内容长大于零再插入
            if(pojo.getBackupLogMsg().length>0){
                xtBackupLogMsgMapper.insert(pojo);
            }
        }
    }

    public Object getPageList(Map map) throws Exception  {
        // 分页初始化
        this.pageListInit(map);
        // 获取查询列表
        List<XtBackupLogMsgPojo> list = xtBackupLogMsgMapper.findAll(map);
        for (XtBackupLogMsgPojo p : list) {
            p.setBackupLogMsgInfo(new String(p.getBackupLogMsg(),"UTF-8"));
        }
        // 封装到PageInfo对象中
        PageInfo pageInfo = new PageInfo(list);
        MIniUIGridResultMap resultMap = new MIniUIGridResultMap(pageInfo);
        return resultMap;
    }

    /**
     * 创建日志对象
     * @param entityClass
     * @param tableId
     * @param operTitle
     * @param operMemo
     * @param smsg
     * @return
     */
    public XtBackupLogMsgPojo createLogPojo( Class<?> entityClass, String tableId, String operTitle, String operMemo, String pojoName,String smsg) throws UnsupportedEncodingException {
        XtBackupLogMsgPojo xtBackupLogMsgPojo = new XtBackupLogMsgPojo();
        Date systime = DateUtil.getSysDateTime();
        xtBackupLogMsgPojo.setId(getSysStrId());
        //获取对象上的注解信息
        Table table = entityClass.getAnnotation(Table.class);
        xtBackupLogMsgPojo.setTableName(table.name().toUpperCase());
        xtBackupLogMsgPojo.setTableId(tableId);
        xtBackupLogMsgPojo.setOperTitle(operTitle);
        xtBackupLogMsgPojo.setOperMemo(operMemo);
        xtBackupLogMsgPojo.setPojoName(pojoName);
        xtBackupLogMsgPojo.setBackupLogMsg(DataTypeUtil.toNotNullString(smsg).getBytes("UTF-8"));
        xtBackupLogMsgPojo.setCreateTime(systime);
        xtBackupLogMsgPojo.setCreateTimeShort(Long.valueOf(DateUtil.date2short(systime)));
        xtBackupLogMsgPojo.setCreateUserId(getLoginCzyId());
        xtBackupLogMsgPojo.setCreateUserName(getLoginCzyName());
        return xtBackupLogMsgPojo;
    }

    /**
     * 获取新实体类全貌
     * @param oper
     * @param newEntityIntance
     * @param oldEntityIntance
     * @return
     * @throws Exception
     */
    private Object getNewEntityIntance(String oper, Object newEntityIntance, Object oldEntityIntance) throws Exception {
        Object tempNewEntityIntance = newEntityIntance;
        if (!SysConstant.OPER_ADD.equals(oper) && !SysConstant.OPER_DELETE.equals(oper) ) {//修改Pojo
            // 但是因为有dao提供了updateIgnoreNull方法，所以传入的newEntityIntance仅仅是局部的值，所以要根据旧实体和改变后的实体综合得到一个修改后的实体全貌。
            tempNewEntityIntance = cloneAndMergeInstance(oldEntityIntance, newEntityIntance);
        }
        return tempNewEntityIntance;
    }

    /**
     * 克隆出一个实体类，用修改之前的Pojo对象加修改后的增量部分，合并得出修改后的Pojo对象全貌
     * @param oldEntityIntance
     * @param newEntityIntance
     * @return
     * @throws Exception
     */
    private Object cloneAndMergeInstance(Object oldEntityIntance, Object newEntityIntance) throws Exception {
        if (oldEntityIntance == null){
            throw new Exception("改变之前的Pojo不能为空。");
        }

        if (newEntityIntance == null){
            throw new Exception("改变之后的Pojo不能为空。");
        }


        oldEntityIntance = JSON.parseObject(JSON.toJSONString(oldEntityIntance), newEntityIntance.getClass());
        if (!oldEntityIntance.getClass().getName().equals(newEntityIntance.getClass().getName())){
            throw new Exception(oldEntityIntance.getClass().getName() + "不能和" + newEntityIntance.getClass().getName() + "相比较。");
        }

        try {
            Class<?> oldCls = oldEntityIntance.getClass();
            Class<?> newCls = newEntityIntance.getClass();

            Object cloneOldEntityIntance = oldEntityIntance.getClass().newInstance();
            PropertyUtils.copyProperties(cloneOldEntityIntance, oldEntityIntance);//这里做克隆，是为了防止对象的引用被破坏

            Field[] fieldList = DataTypeUtil.getSuperField(oldEntityIntance);

            for (int i = 0; i < fieldList.length; i++) {
                Field field = fieldList[i];
                String prop_name = field.getName();
                String firstCharUpperPropName = DataTypeUtil.firstCharUpper(prop_name);
                String getMethodName = "get" + firstCharUpperPropName;
                String setMethodName = "set" + firstCharUpperPropName;

                try {
                    Method old_gm = oldCls.getMethod(getMethodName, null);
                    Object new_v = old_gm.invoke(newEntityIntance, null);//用户修改后的值（增量变化部分）

                    if (new_v != null) {//这里不能用DataTypeUtil.isEmptyStr方法，因为传入的值有可能是空字符串，而不是空。
                        Method new_gm = newCls.getMethod(setMethodName,new_v.getClass());
                        new_gm.invoke(cloneOldEntityIntance,new_v);
                    }
                } catch (Exception e) {
                    LoggerFactory.getLogger(ContrastUtils.class).error(e.getMessage());
                    continue;
                }
            }
            return cloneOldEntityIntance;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public Object cloneJsonObjToInstance(JSONObject jsonObject, Object obj) throws Exception {
        Field[] fieldList = DataTypeUtil.getSuperField(obj);
        for (int i = 0; i < fieldList.length; i++){
            Field field = fieldList[i];
            fieldList[i].setAccessible(true);
            try {
                Object value = jsonObject.get(DataTypeUtil.humpToLine2(field.getName()));//旧对象通过jsonObject.get获取
                if (value != null) {//这里不能用DataTypeUtil.isEmptyStr方法，因为传入的值有可能是空字符串，而不是空。
                    PropertyDescriptor newPd = new PropertyDescriptor(field.getName(), obj.getClass());
                    Method writeMethod = newPd.getWriteMethod();
                    if(value instanceof BigDecimal){
                        writeMethod.invoke(obj,((BigDecimal) value).doubleValue());
                    }
                    else if(value instanceof Long ){
                        writeMethod.invoke(obj,((Long) value).longValue());
                    }
                    else if(value instanceof Integer){
                        writeMethod.invoke(obj, DataTypeUtil.toLongObject(((Integer) value).intValue()));
                    }
                    else{
                        writeMethod.invoke(obj,value);
                    }
                }
            } catch (Exception e) {
                LoggerFactory.getLogger(ContrastUtils.class).error(e.getMessage());
                continue;
            }
        }
        return obj;
    }


    @Transactional(rollbackFor = {Exception.class})
    public void batchInsert(List<XtBackupLogMsgPojo> xtBackupLogMsgPojoList) {
        if(xtBackupLogMsgPojoList!=null && !xtBackupLogMsgPojoList.isEmpty()){
            for(XtBackupLogMsgPojo pojo : xtBackupLogMsgPojoList){
                xtBackupLogMsgMapper.insert(pojo);
            }
        }
    }
}
